package com.sojpt.boot;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.jfinal.aop.Invocation;
import com.jfinal.core.Action;
import com.jfinal.core.ActionReporter;
import com.jfinal.core.Controller;
import com.jfinal.core.ControllerFactory;
import com.jfinal.core.JFinal;
import com.jfinal.render.Render;

@Aspect
@Component
@Order(10)
public class SoJptControllerAspectConfig {

	@Autowired
	private ActiveRecordPluginProperties arpProperties;

	@Autowired
	private ServerProperties serverProperties;
	
	@Autowired
    private HttpServletRequest request; //自动注入request
	
	@Autowired
    private HttpServletResponse response; //自动注入request
	/**
	 * *匹配带有 AdminOnlyMethod Annotation的方法
	 */
	@Pointcut("execution(public * com.jfinal.core.Controller+.*(..))")
	public void sojptMethod() {
		
	}

	@Around("sojptMethod()")
	// synchronized 解决spring cloud (多线程) 环境下报 UT010005: Cannot call
	// getOutputStream(), getWriter() already called 的异常 因为Spring Boot Controller默认是单例模式
	public Object around(ProceedingJoinPoint jp) throws Throwable {

		Object obj = null;
		long s = System.currentTimeMillis();

		String[] urlPara = { null };
		String contextPath = serverProperties.getServlet().getContextPath();
		String target = contextPath == null ? request.getRequestURI() : request.getRequestURI().substring(contextPath.length());

		Action action = JFinal.me().getAction(target, urlPara);
		if (action == null) {
			return jp.proceed(jp.getArgs());
		}

		Method method = jp.getTarget().getClass().getMethod("_init_", Action.class, HttpServletRequest.class,
				HttpServletResponse.class, String.class);
		method.invoke(jp.getTarget(), action, request, response, urlPara[0]);

		ControllerFactory controllerFactory = JFinal.me().getConstants().getControllerFactory();
		Controller controller = controllerFactory.getController(action.getControllerClass());
		if (JFinal.me().getConstants().getInjectDependency()) {
			com.jfinal.aop.Aop.inject(controller);
		}
		controller._init_(action, request, response, urlPara[0]);

		if (arpProperties.getIsDevMode()) {
			if (ActionReporter.isReportAfterInvocation(request)) {
				obj = new Invocation(action, controller, jp).invoke();
				ActionReporter.report(target, controller, action);
			} else {
				ActionReporter.report(target, controller, action);
				obj = new Invocation(action, controller, jp).invoke();
			}
		} else {
			obj = new Invocation(action, controller, jp).invoke();
		}
		
		Render render = (Render) jp.getTarget().getClass().getMethod("getRender").invoke(jp.getTarget());
		if (render == null)
			render = controller.getRender(); // 拦截器的render
		if (render != null) { // controller使用了render方法

			render.setContext(request, response);

			try {
				render.render();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				obj = null;
			}
		}
		
		controllerFactory.recycle(controller);
		long e = System.currentTimeMillis();
		System.err.println("耗时: " + (e - s) + " 毫秒");

		return obj;
	}

}